import { persistentWritable, writable } from '$utils/persist';
import { onMount } from 'svelte';
import type { Writable } from 'svelte/store';

type CartItem = Partial<Product.Detail>;

type CartListType = CartItem[];

const getDefaultCart = (): CartListType => [];

export const useCartStore = () => {
	const list = persistentWritable<CartListType>('cart', getDefaultCart());

	const mergeList = (
		data: CartListType,
		filter: (v: Partial<Product.Detail>) => boolean = () => true
	) => {
		list.update((value) => {
			data.forEach((item) => {
				item.num = item.moq || 0;
				const has = value.some((i) => i.id === item.id);
				if (!has) value.push(item);
				else Object.assign(value.find((i) => i.id === item.id)!, item); // update
			});

			value.forEach((i) => {
				if (i.add_date) return;
				i.add_date = new Date().getTime();
			});

			return value.filter(filter);
		});
	};

	const addCartItem = (item: CartItem) => {
		return new Promise((commitHandleStatus) => {
			list.update((value) => {
				item.add_date = new Date().getTime();
				const has = value.some((i) => i.id === item.id);
				if (!has) value.push(item);
				else Object.assign(value.find((i) => i.id === item.id)!, item); // update
				const resultOfUpdate = !has ? true : false;
				commitHandleStatus(resultOfUpdate);
				return value;
			});
		});
	};

	const removeCartItem = (id: number) => {
		const item: Partial<Product.Detail> = {};
		list.update((list) => {
			Object.assign(
				item,
				list.find((i) => i.id === id)
			);
			return list.filter((item: CartItem) => item.id !== id);
		});
		return item;
	};

	const clearAllCarts = () => {
		list.set(getDefaultCart());
	};

	return {
		cartList: list,
		addCartItem,
		removeCartItem,
		clearAllCarts,
		mergeList
	};
};

type CartStoreHookResultType = {
	cartList: Writable<CartListType>;
	addCartItem: (item: CartItem) => Promise<unknown>;
	removeCartItem: (id: number) => Partial<Product.Detail>;
	clearAllCarts: () => void;
	mergeList: (data: CartListType, filter?: (v: Partial<Product.Detail>) => boolean) => void;
};

export const getCartStore = () => {
	const result: IObject = {};

	const merge_store = () => Object.assign(result, useCartStore());

	onMount(merge_store);

	return result as unknown as CartStoreHookResultType;
};
